/**
 * @FileName: StoreSetController.java
 * @Author
 * @Description:
 * @Date 2016年1月6日 下午3:46:52
 * @CopyRight ZTE Corporation
 */
package cn.hpclub.server.controller.client;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

import org.dom4j.Document;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.jfinal.kit.StrKit;
import com.jfinal.plugin.activerecord.Db;
import com.jfinal.plugin.activerecord.Record;
import com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException;

import cn.hpclub.server.constant.Constant;
import cn.hpclub.server.model.MemberOrg;
import cn.hpclub.server.model.Reward;
import cn.hpclub.server.model.SalePromotion;
import cn.hpclub.server.restful.API;
import cn.hpclub.server.util.DESAS;

@API("/SaleRecover/recover")
public class SaleRecoverController extends BaseClientController<MemberOrg>{
    private static Logger       log    = LoggerFactory.getLogger(SaleRecoverController.class);
    private static final Logger logger = LoggerFactory.getLogger(SaleRecoverController.class);

    public static String        DATA   = "/root/data/";

    /**
     * @Title: 恢复异常的sale_promotion_record
     * @Description:
     */
    public void recover(){

        int count_total = 0;
        int count_success = 0;
        int count_exist = 0;
        int count_fail = 0;
        try{
            String temp;
            String data;
            String start_time = getPara("start_time");
            String end_time = getPara("end_time");
            // start_time = "2016-05-16";
            String sql = "select xml from sales_promotion_record where ";
            if(!StrKit.isBlank(start_time)){
                sql += "date_format(add_time,'%Y-%m-%d')>='" + start_time + "'";
            } else{
                sql += "date_format(add_time,'%Y-%m-%d')>=date_format(now(),'%Y-%m-%d')";
            }

            if(!StrKit.isBlank(end_time)){
                sql += " and date_format(add_time,'%Y-%m-%d')<='" + end_time + "'";
            } else{
                sql += " and date_format(add_time,'%Y-%m-%d')<=date_format(now(),'%Y-%m-%d')";
            }
            log.debug("SaleRecoverController sql=" + sql);
            List<Record> list = Db.find(sql);
            count_total = list.size();
            log.info("SaleRecoverController count_total=" + count_total);
            for(Record r : list){
                if(StrKit.isBlank(r.getStr("xml"))){
                    count_fail++;
                    continue;
                }
                // temp = updateSalePromotion(r.getStr("xml"));
                temp = rechargeCallbackEx(r.getStr("xml"));
                // log.info("SaleRecoverController temp=" + temp);
                if(temp.contains("success")){
                    count_success++;
                } else if(temp.contains("exist")){
                    count_exist++;
                } else{
                    log.debug("SaleRecoverController error xml=" + r.getStr("xml"));
                    count_fail++;
                }
            }
        }
        catch(Exception e){

        }
        log.info("SaleRecoverController result=" + "总计" + count_total + "条。成功" + count_success + "条。存在" + count_exist
                + "条。失败" + count_fail + "条。");
        renderText("总计" + count_total + "条。成功" + count_success + "条。存在" + count_exist + "条。失败" + count_fail + "条。");

    }

    /**
     * 大掌柜业务回调数据解析
     * 
     * @param request
     * @throws Exception
     */
    public String rechargeCallbackEx(String request){
        try{
            SAXReader saxReader = new SAXReader();
            Document document = saxReader.read(new ByteArrayInputStream(request.getBytes()));

            SalePromotion sale = new SalePromotion();
            // 常量字段 10
            updateSaleConstants(sale);
            // 通用字段 14
            updateCommonfields(document, sale);
            // 解析 foreign_content 3
            parseForeignContent(document, sale);
            // 更新机构ID
            updateOrgId(sale);
            // 更新酬金
            updateReward(sale);

            sale.save();
        }
        catch(Exception e){
            if(e.getMessage() != null && e.getMessage().contains("Duplicate entry")){
                return "exist";
            } else{
                return (new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
            }
        }
        return "success";
    }

    private void updateCommonfields(Document document, SalePromotion sale){
        // 原始数据保存到xmlData字段 异常:asXML
        sale.set(SalePromotion.XMLDATA, document.asXML());
        // 移动业务订单号
        sale.set(SalePromotion.ORDER_ID, getNodeStringValue(document, SalePromotion.ORDER_ID));
        // 大掌柜业务订单号
        sale.set(SalePromotion.THIRDPART_ID, getNodeStringValue(document, SalePromotion.THIRDPART_ID));
        // 支付金额
        sale.set(SalePromotion.AMOUNT, getNodeIntegerValue(document, SalePromotion.AMOUNT));
        // 电话号码
        sale.set(SalePromotion.PHONE_NO, getNodeStringValue(document, SalePromotion.PHONE_NO));
        // 办理时间
        sale.set(SalePromotion.TIME, getNodeStringValue(document, SalePromotion.TIME));
        // 回调状态
        sale.set(SalePromotion.RETURN_CODE, getNodeStringValue(document, SalePromotion.RETURN_CODE));
        // 回调信息
        sale.set(SalePromotion.RETURN_MSG, getNodeStringValue(document, SalePromotion.RETURN_MSG));
        // 系统id
        sale.set(SalePromotion.SYSTEMID, getNodeIntegerValue(document, SalePromotion.SYSTEMID));
        // 分销平台
        sale.set(SalePromotion.SOURCE, getNodeIntegerValue(document, SalePromotion.SOURCE));
        // 接口
        sale.set(SalePromotion.METHOD, getNodeStringValue(document, SalePromotion.METHOD));
        // 资费代码
        sale.set(SalePromotion.BUSINESS_CODE, getNodeStringValue(document, SalePromotion.BUSINESS_CODE));
        // 购买方式
        sale.set(SalePromotion.SALETYPE, getNodeStringValue(document, SalePromotion.SALETYPE));
        // 用户ID
        sale.set(SalePromotion.USERID, getNodeIntegerValue(document, SalePromotion.USERID));
    }

    private void updateOrgId(SalePromotion sale){
        try{
            Integer userId = sale.getInt(SalePromotion.USERID);
            if(null != userId && !userId.equals(0)){
                Record r = Db.findFirst("select org_id from member_org where id=" + userId);
                if(null != r){
                    sale.set(SalePromotion.ORG_ID, r.getInt("org_id"));
                }
            }
        }
        catch(Exception e){

        }
    }

    private void updateSaleConstants(SalePromotion sale){
        sale.set(SalePromotion.ID, 0);
        sale.set(SalePromotion.APPID, 100000056);
        sale.set(SalePromotion.IS_USED, 0);
        sale.set(SalePromotion.USED_TIME, null);
        sale.set(SalePromotion.WIN_TYPE, null);
        sale.set(SalePromotion.WIN_NAME, null);
        sale.set(SalePromotion.INTE_RES_CODE, null);
        sale.set(SalePromotion.INTE_RES_MSG, null);
        sale.set(SalePromotion.ISDELETE, 0);
        sale.set(SalePromotion.ISFIXDATA, 0);
    }

    private void updateReward(SalePromotion sale){
        List<Record> listReward = SalePromotion.dao
                .findReward(sale.getInt(SalePromotion.USERID), sale.getStr(SalePromotion.BUSINESS_CODE),
                            sale.getInt(SalePromotion.ORG_ID), sale.getInt(SalePromotion.MODULEID));

        if(listReward == null || listReward.size() <= 0
                || Integer.parseInt(sale.getStr(SalePromotion.RETURN_CODE)) != 0){
            sale.set(SalePromotion.REWARD, 0.00);
        } else{
            Record reward = listReward.get(0);
            Double temp = 0.00;
            Double sum = reward.getBigDecimal("sum").doubleValue();
            Double sumModule = reward.getBigDecimal("sumModule").doubleValue();
            Double clerk = 0.00;
            boolean tag_module = false;
            boolean tag_sum = false;
            if(reward.getLong("count") <= 0){
                temp = reward.getBigDecimal(Reward.FIRST_REWARD).doubleValue();
            } else{
                temp = reward.getBigDecimal(Reward.NORMAL_REWARD).doubleValue();
            }

            List<Record> listClerk = SalePromotion.dao.findClerkReward(sale.getInt(SalePromotion.MODULEID),
                                                                       sale.getInt(SalePromotion.ORG_ID));
            if(listClerk != null && listClerk.size() >= 1){
                for(Record r : listClerk){
                    if(r.getInt("moduleid") == sale.getInt(SalePromotion.MODULEID)){
                        clerk = r.getBigDecimal("single_cap").doubleValue() <= 0 ? Double.MAX_VALUE
                                : r.getBigDecimal("single_cap").doubleValue();

                        sumModule = sumModule >= clerk ? 0.00 : clerk - sumModule;
                        tag_module = true;
                        // sumModule = sumModule >=
                        // r.getBigDecimal("single_cap").doubleValue() ? 0.00
                        // : r.getBigDecimal("single_cap").doubleValue() -
                        // sumModule;
                    } else{
                        clerk = r.getBigDecimal("single_cap").doubleValue() <= 0 ? Double.MAX_VALUE
                                : r.getBigDecimal("single_cap").doubleValue();

                        sum = sum >= clerk ? 0.00 : clerk - sum;
                        tag_sum = true;
                        // sum = sum >=
                        // r.getBigDecimal("single_cap").doubleValue() ? 0.00
                        // : r.getBigDecimal("single_cap").doubleValue() - sum;
                    }
                }
            }

            if(!tag_module){
                sumModule = Double.MAX_VALUE;
            }
            if(!tag_sum){
                sum = Double.MAX_VALUE;
            }
            temp = min(temp, sum, sumModule);

            sale.set(SalePromotion.REWARD, temp);
        }
    }

    private void parseForeignContent(Document document, SalePromotion sale) throws Exception{
        String foreign_content = getNodeStringValue(document, SalePromotion.FOREIGN_CONTENT);
        if(null != foreign_content){
            String[] items = foreign_content.split("_");
            for(int i = 0; i < items.length; i++){
                String item = items[i];
                // 购买方式
                if(item.contains("saleType")){
                    sale.set(SalePromotion.SALETYPE, getItemStringValue(item));
                }
                // 模块ID
                setSaleIntegerValue(sale, item, SalePromotion.MODULEID);
                // moduleCode
                setSaleStringValue(sale, item, SalePromotion.MODULECODE);

                // 回调的fxstr
                if(item.contains(SalePromotion.FXSTR)){
                    // 保存 fxstr 原始数据
                    String fxStr = getItemStringValue(item);
                    sale.set(SalePromotion.FXSTR, fxStr);

                    // 进一步解析fxstr
                    parseFsStr(sale, fxStr);
                }
            }
        }
    }

    private void parseFsStr(SalePromotion sale, String fxStr) throws Exception{
        if(null != fxStr && !"".equals(fxStr)){
            DESAS des = new DESAS();
            String desFxStr = des.decrypt(fxStr);
            if(null != desFxStr && !"".equals(desFxStr)){
                String[] fsContents = desFxStr.split("#");
                // fx =
                // "{\"params\":\"11#10407088#5291680#20160217002809#1095602#4001#Q1o=\"}";
                if(fsContents.length > 5){
                    sale.set(SalePromotion.BUSINESS_CODE, fsContents[5]);
                }
                if(fsContents.length > 2){
                    sale.set(SalePromotion.USERID, Integer.parseInt(fsContents[2]));
                    // MODULECODE
                    sale.set(SalePromotion.MODULECODE, 8000);
                }
            }
        }
    }

    private void setSaleIntegerValue(SalePromotion sale, String item, String node){
        if(item.contains(node)){
            sale.set(node, getItemIntegerValue(item));
        }
    }

    private void setSaleStringValue(SalePromotion sale, String item, String node){
        if(item.contains(node)){
            sale.set(node, getItemStringValue(item));
        }
    }

    private Integer getItemIntegerValue(String item){
        try{
            String element[] = item.split("=");
            if(element.length > 1){
                return Integer.parseInt(element[1]);
            }
        }
        catch(Exception e){}

        return 0;
    }

    private String getItemStringValue(String item){
        try{
            String element[] = item.split("=");
            if(element.length > 1){
                return element[1];
            }
        }
        catch(Exception e){}

        return null;
    }

    private String getNodeStringValue(Document document, String node){
        try{
            Node result = document.selectSingleNode(DATA + node);
            if(null != result){
                return result.getText().trim();
            }
        }
        catch(Exception e){}

        return null;
    }

    private Integer getNodeIntegerValue(Document document, String node){
        try{
            String result = getNodeStringValue(document, node);
            if(null != result){
                return Integer.parseInt(result);
            }
        }
        catch(Exception e){}

        return 0;
    }

    public String getHttpByPostBody(String url, String data){
        HttpURLConnection connect = null;
        try{

            connect = (HttpURLConnection)new java.net.URL(url).openConnection();
            connect.setRequestMethod("POST");
            connect.setDoOutput(true);
            connect.setDoInput(true);
            connect.setUseCaches(false);
            connect.setRequestProperty("Content-type", "text/plain;charset=UTF-8");
            connect.setConnectTimeout(15000);
            connect.setReadTimeout(15000);

            DataOutputStream out = new DataOutputStream(connect.getOutputStream());
            out.writeBytes(data);
            out.flush();
            out.close();
            connect.connect();
            if(connect.getResponseCode() == 200){
                InputStream is = connect.getInputStream();
                ByteArrayOutputStream bytestream = new ByteArrayOutputStream();
                int ch;
                while((ch = is.read()) != -1){
                    bytestream.write(ch);
                }
                is.close();
                byte[] result = bytestream.toByteArray();
                // System.out.println("getHttpByPostBody result=" + new
                // String(result));
                return new String(result);
            } else{
                return "getHttpByPostBody exception";
            }
        }
        catch(Exception e){
            e.printStackTrace();
        }
        finally{
            connect.disconnect();
        }
        return "getHttpByPostBody exception";
    }

    private String updateSalePromotion(String data){
        try{
            Document document = null;
            String DATA = "/root/data/";
            String fx = null;
            SAXReader saxReader = new SAXReader();
            document = saxReader.read(new ByteArrayInputStream(data.getBytes()));

            SalePromotion sale = new SalePromotion();
            sale.set(SalePromotion.ID, 0);
            sale.set(SalePromotion.APPID, Constant.APPID);
            sale.set(SalePromotion.ORDER_ID, document.selectSingleNode(DATA + SalePromotion.ORDER_ID).getText().trim());
            sale.set(SalePromotion.AMOUNT,
                     Integer.parseInt(document.selectSingleNode(DATA + SalePromotion.AMOUNT).getText().trim()));
            sale.set(SalePromotion.PHONE_NO, document.selectSingleNode(DATA + SalePromotion.PHONE_NO).getText().trim());
            sale.set(SalePromotion.TIME, document.selectSingleNode(DATA + SalePromotion.TIME).getText().trim());
            sale.set(SalePromotion.IS_USED, 0);
            sale.set(SalePromotion.USED_TIME, null);
            sale.set(SalePromotion.WIN_TYPE, null);
            sale.set(SalePromotion.WIN_NAME, null);
            sale.set(SalePromotion.RETURN_CODE,
                     document.selectSingleNode(DATA + SalePromotion.RETURN_CODE).getText().trim());
            sale.set(SalePromotion.RETURN_MSG,
                     document.selectSingleNode(DATA + SalePromotion.RETURN_MSG).getText().trim());

            sale.set(SalePromotion.INTE_RES_CODE, null);
            sale.set(SalePromotion.INTE_RES_MSG, null);
            sale.set(SalePromotion.ISDELETE, 0);
            sale.set(SalePromotion.ISFIXDATA, 0);
            sale.set(SalePromotion.XMLDATA, document.asXML());

            if(document.selectSingleNode(DATA + SalePromotion.THIRDPART_ID) != null){// 充值缴费回调

                sale.set(SalePromotion.SYSTEMID, 0);
                sale.set(SalePromotion.SOURCE, 0);
                sale.set(SalePromotion.METHOD, null);
                String[] foreign_content = document.selectSingleNode(DATA + "foreign_content").getText().trim()
                        .split("_");
                for(int i = 0; i < foreign_content.length; i++){
                    if(foreign_content[i].contains("saleType")){
                        sale.set(SalePromotion.SALETYPE,
                                 foreign_content[i].substring(foreign_content[i].lastIndexOf('=') + 1));
                    }
                    if(foreign_content[i].contains(SalePromotion.FXSTR)){
                        sale.set(SalePromotion.FXSTR,
                                 foreign_content[i].substring(foreign_content[i].lastIndexOf('=') + 1));

                    }
                    if(foreign_content[i].contains(SalePromotion.MODULEID)){
                        sale.set(SalePromotion.MODULEID, Integer
                                .parseInt(foreign_content[i].substring(foreign_content[i].lastIndexOf('=') + 1)));

                    }
                }

                // HashMap<String, Object> hm = new HashMap<String, Object>();
                // hm.put(SalePromotion.FXSTR,
                // sale.getStr(SalePromotion.FXSTR));
                // fx = HttpUtil.getHttpByGet(URL_DECODE, hm);
                // // fx =
                // //
                // "{\"params\":\"11#10407088#5291680#20160217002809#1095602#4001#Q1o=\"}";
                // logger.debug("SaleRecoverController fx=" + fx);

                DESAS des = new DESAS();
                fx = des.decrypt(sale.getStr(SalePromotion.FXSTR));
                // logger.debug("SaleRecoverController fx=" + fx);
                foreign_content = fx.split("#");

                sale.set(SalePromotion.BUSINESS_CODE, foreign_content[5]);
                sale.set(SalePromotion.USERID, Integer.parseInt(foreign_content[2]));
                Record r = Db.findFirst("select " + MemberOrg.ORG_ID + " from " + Constant.Table.MEMBER_ORG + " where "
                        + MemberOrg.ID + "=" + foreign_content[2].trim());
                sale.set(SalePromotion.ORG_ID, r.getInt(MemberOrg.ORG_ID));
                sale.set(SalePromotion.MODULECODE, 8000);
            } else{
                Record r = Db.findFirst("select " + MemberOrg.ORG_ID + " from " + Constant.Table.MEMBER_ORG + " where "
                        + MemberOrg.ID + "=" + document.selectSingleNode(DATA + SalePromotion.USERID).getText().trim());
                sale.set(SalePromotion.ORG_ID, r.getInt(MemberOrg.ORG_ID));
                // sale.set(SalePromotion.ORG_ID,
                // Integer.parseInt(document.selectSingleNode(DATA +
                // SalePromotion.STOREID).getText().trim()));
                sale.set(SalePromotion.USERID,
                         Integer.parseInt(document.selectSingleNode(DATA + SalePromotion.USERID).getText().trim()));
                sale.set(SalePromotion.BUSINESS_CODE,
                         document.selectSingleNode(DATA + SalePromotion.BUSINESS_CODE).getText().trim());
                sale.set(SalePromotion.SYSTEMID,
                         Integer.parseInt(document.selectSingleNode(DATA + SalePromotion.SYSTEMID).getText().trim()));
                sale.set(SalePromotion.SOURCE,
                         Integer.parseInt(document.selectSingleNode(DATA + SalePromotion.SOURCE).getText().trim()));
                sale.set(SalePromotion.METHOD, document.selectSingleNode(DATA + "methodName").getText().trim());
                sale.set(SalePromotion.SALETYPE,
                         Integer.parseInt(document.selectSingleNode(DATA + SalePromotion.SALETYPE).getText().trim()));
                sale.set(SalePromotion.FXSTR, null);
                String[] foreign_content = document.selectSingleNode(DATA + "foreign_content").getText().trim()
                        .split("_");
                int moduleId = 0;
                String moduleCode = "";
                for(int i = 0; i < foreign_content.length; i++){
                    if(foreign_content[i].contains(SalePromotion.MODULEID)){
                        moduleId = Integer
                                .parseInt(foreign_content[i].substring(foreign_content[i].lastIndexOf('=') + 1));

                    }

                    if(foreign_content[i].contains(SalePromotion.MODULECODE)){
                        moduleCode = foreign_content[i].substring(foreign_content[i].lastIndexOf('=') + 1);

                    }
                }
                sale.set(SalePromotion.MODULECODE, moduleCode);
                sale.set(SalePromotion.MODULEID, moduleId);

            }

            List<Record> listReward = SalePromotion.dao
                    .findReward(sale.getInt(SalePromotion.USERID), sale.getStr(SalePromotion.BUSINESS_CODE),
                                sale.getInt(SalePromotion.ORG_ID), sale.getInt(SalePromotion.MODULEID));

            if(listReward == null || listReward.size() <= 0
                    || Integer.parseInt(sale.getStr(SalePromotion.RETURN_CODE)) != 0){
                sale.set(SalePromotion.REWARD, 0.00);
            } else{
                Record reward = listReward.get(0);
                Double temp = 0.00;
                Double sum = reward.getBigDecimal("sum").doubleValue();
                Double sumModule = reward.getBigDecimal("sumModule").doubleValue();
                Double clerk = 0.00;
                boolean tag_module = false;
                boolean tag_sum = false;
                if(reward.getLong("count") <= 0){
                    temp = reward.getBigDecimal(Reward.FIRST_REWARD).doubleValue();
                } else{
                    temp = reward.getBigDecimal(Reward.NORMAL_REWARD).doubleValue();
                }

                List<Record> listClerk = SalePromotion.dao.findClerkReward(sale.getInt(SalePromotion.MODULEID),
                                                                           sale.getInt(SalePromotion.ORG_ID));
                if(listClerk != null && listClerk.size() >= 1){
                    for(Record r : listClerk){
                        if(r.getInt("moduleid") == sale.getInt(SalePromotion.MODULEID)){
                            clerk = r.getBigDecimal("single_cap").doubleValue() <= 0 ? Double.MAX_VALUE
                                    : r.getBigDecimal("single_cap").doubleValue();

                            sumModule = sumModule >= clerk ? 0.00 : clerk - sumModule;
                            tag_module = true;
                            // sumModule = sumModule >=
                            // r.getBigDecimal("single_cap").doubleValue() ?
                            // 0.00
                            // : r.getBigDecimal("single_cap").doubleValue() -
                            // sumModule;
                        } else{
                            clerk = r.getBigDecimal("single_cap").doubleValue() <= 0 ? Double.MAX_VALUE
                                    : r.getBigDecimal("single_cap").doubleValue();

                            sum = sum >= clerk ? 0.00 : clerk - sum;
                            tag_sum = true;
                            // sum = sum >=
                            // r.getBigDecimal("single_cap").doubleValue() ?
                            // 0.00
                            // : r.getBigDecimal("single_cap").doubleValue() -
                            // sum;
                        }
                    }
                }

                if(!tag_module){
                    sumModule = Double.MAX_VALUE;
                }
                if(!tag_sum){
                    sum = Double.MAX_VALUE;
                }
                temp = min(temp, sum, sumModule);

                sale.set(SalePromotion.REWARD, temp);

            }

            sale.save();
        }
        catch(MySQLIntegrityConstraintViolationException me){

            if(me.getMessage() != null && me.getMessage().contains("Duplicate entry")){
                return "exist";
            } else{
                return (new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
            }
        }
        catch(Exception e){

            if(e.getMessage() != null && e.getMessage().contains("Duplicate entry")){
                return "exist";
            } else{
                return (new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
            }
        }
        return "success";
    }

    private double min(double reward, double sum, double sumModule){
        double min = reward;
        if(sum < min){
            min = sum;
        }
        if(sumModule < min){
            min = sumModule;
        }
        return Double.parseDouble(new DecimalFormat("######0.00").format(min));
    }

}
